import 'dart:math';

import 'package:flutter/material.dart';

/// Curve 是一个抽象类，它有很多实现子类。最通用的是 Cubic ，传入四个值。
// 下面来看一下，如何使用 CurveTween 让动画的变化速率具有曲线效果。
// Curve --- 抽象类
// 	|--- Cubic 四值三阶贝塞尔曲线
// 	|--- FlippedCurve  翻转曲线
// 	|--- SawTooth 锯齿形曲线
// 	|--- Threshold 0~阈值 曲线
// 	|--- ...
class CurveBox extends StatefulWidget {
  final Color color;
  final Curve curve;

  CurveBox(
      {Key? key, this.color = Colors.lightBlue, this.curve = Curves.linear})
      : super(key: key);

  @override
  State<CurveBox> createState() => _CurveBoxState();
}

class _CurveBoxState extends State<CurveBox>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _angleAnimation;

  @override
  void initState() {
    super.initState();
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 3));
    _angleAnimation = CurveTween(curve: widget.curve).animate(_controller);

    /// 动画器的方法
    // forward 和 reverse 方法
    // |--- forward({ double from })  执行运动直到上界，可指定初始值。(执行完就会停止)
    // |--- reverse({ double from })  执行运动直到下界，可指定初始值。(执行完就会停止)

    // repeat 重复执行
    // repeat
    // 	|--- double? min, // 下界
    //  |--- double? max, // 上界
    //  |--- bool reverse = false, // 是否反转
    //  |--- Duration? period // 周期

    // fling 方法
    // fling 也就是 猛冲，可以给一个速度，默认为 1 。

    // stop 和 reset
    // stop 方法是让 _ticker 停止，这样动画也就停止了。可以传入一个 bool 值，用于是否取消。
    // reset 方法也很简单，就是将当前值置为下界。

    _controller.repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      size: const Size(100, 100),
      painter: CurveBoxPainter(_controller, _angleAnimation),
    );
  }
}

class CurveBoxPainter extends CustomPainter {
  final Animation<double> repaint;
  Animation<double> angleAnimation;
  final Paint _paint = Paint();

  final double strokeWidth = 5;

  CurveBoxPainter(this.repaint, this.angleAnimation) : super(repaint: repaint);

  @override
  void paint(Canvas canvas, Size size) {
    canvas.clipRect(Offset.zero & size);
    canvas.translate(size.width / 2, size.height / 2);

    _drawRing(canvas, size);
    _drawRedCircle(canvas, size);
    _drawGreenCircle(canvas, size);
  }

  // 绘制环
  void _drawRing(Canvas canvas, Size size) {
    _paint
      ..color = Colors.blue
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth;
    canvas.drawCircle(Offset.zero, size.width / 2 - strokeWidth, _paint);
  }

  // 绘制红球
  void _drawRedCircle(Canvas canvas, Size size) {
    canvas.save();
    canvas.rotate(angleAnimation.value * 2 * pi);
    canvas.drawCircle(
        Offset.zero.translate(0, -(size.width / 2 - strokeWidth)),
        strokeWidth,
        _paint
          ..color = Colors.red
          ..style = PaintingStyle.fill);
    canvas.restore();
  }

  // 绘制绿球
  void _drawGreenCircle(Canvas canvas, Size size) {
    canvas.save();
    canvas.translate(0, angleAnimation.value * (size.height - 10));
    canvas.drawCircle(
        Offset.zero.translate(0, -(size.width / 2 - strokeWidth)),
        strokeWidth,
        _paint
          ..color = Colors.green
          ..style = PaintingStyle.fill);
    canvas.restore();
  }

  @override
  bool shouldRepaint(covariant CurveBoxPainter oldDelegate) {
    return oldDelegate.repaint != repaint;
  }
}
